<!--
  el-form-item 二次封装
-->
<template>
  <el-form-item
    :class="`vs-form-item ${hasLabelProp? '': 'noLabel'} ${labelTopClsName}`"
    :label="label_"
    :label-width="labelWidth"
    :prop="prop_"
    :error="error"
    :validate-status="validateStatus"
    :inline-message="inlineMessage"
    :show-message="showMessage"
    :size="size"
    :rules="getRules()"
  >
    <template #label>
      <slot name="label">
        <span
          class="label"
        >
          <div class="label-content">
            <span class="label-text">{{ label_ }}</span>
            <Helptip v-if="helptip">{{ helptip }}</Helptip>
            <Helptip
              v-else-if="tipKey"
              :tip-key="tipKey"
              :has-lock="hasTipLock"
            ></Helptip>
            <slot name="helptip"></slot>
          </div>
        </span>
      </slot>
    </template>
    <div class="cont" :style="contStyle">
      <slot>
        <ValueInputer
          v-if="objHas(conf_, 'switch')"
          v-model:value="lastObj[lastKeySwitch]"
          value-type="Boolean"
        />
        <template v-if="isFieldShow">
          <ValueInputer
            v-model:value="lastObj[lastKey]"
            :value-type="valueType"
            :enum-values="conf_.options || []"
            :min="conf_.min || 0"
            :max="conf_.max || 100000000"
            :time-type="conf_.timeType || 'date'"
            :dims="conf_.dims || ''"
            :step="conf_.step || 1"
            :stepStrictly="stepStrictly"
            :rules="getRules()"
            :controls="true"
            :controls-position="conf_.units ? 'right' : ''"
            :readonly="readonly"
            :label="label_"
            :contentWidth="contentWidth"
            :placeholder="placeholder"
            @change="change"
          />
          <ValueInputer
            v-if="conf_.units"
            v-model:value="lastObj[lastKeyUnit]"
            value-type="RadioBtn"
            :enum-values="conf_.units"
            class="units"
          />
        </template>
      </slot>
    </div>
  </el-form-item>
</template>
<script>
import Helptip from '@/components/common/helptip/helptip.vue';
import fItemConfBase from './form-item-config-base.js';
import ValueInputer from '@/components/common/value-inputer/value-inputer.vue';
import { generateRules, generateUrlRule, genRequireRule } from '@/utils/rules.js';
import { objHas } from '@/utils/util';

export default {
  components: {
    Helptip,
    ValueInputer,
  },
  props: {

    // -------- element ui默认传参
    label: String,
    labelWidth: String,
    contWidth: String,
    prop: String,
    rules: [Object, Array],
    error: String,
    validateStatus: String,
    inlineMessage: {
      type: [String, Boolean],
      default: '',
    },
    showMessage: {
      type: Boolean,
      default: true,
    },
    size: String,

    // --------- 自定义传参
    helptip: String,
    tipKey: String,
    hasTipLock: {
      type: Boolean,
      default: true,
    },
    readonly: {
      type: Boolean,
      default: false,
    },
    contentWidth: String, // 设置内容宽度
    labelTop: { // 针对有多行高度的，label会在居中展示效果不好，这个参数可以将label置顶
      type: Boolean,
      default: false,
    },
    placeholder: {
      type: String,
      default: '',
    },

    // --------- 配合form-item-config.js使用的传参
    form: Object, // 顶层对象，一般对应组件的 config.property
    path: String, // 属性路径，如： "map.level"，配合form传参使用
    conf: Object, // 属性配置，结构如 {type: 'number', label: 'xxx', default: 10}
    confs: Object, // 属性配置组合，组合里面根据path找conf
  },
  emits: ['change'],
  data() {
    return {
      lastObj: {},
      lastKey: '',
      lastKeySwitch: '', // 开关
      lastKeyUnit: '', // 数值类型的单位，如%或px
    };
  },
  computed: {
    conf_() {
      let conf = {};
      let confs = this.confs || {};
      confs = { ...fItemConfBase, ...confs };

      if (this.conf) {
        conf = this.conf;
      } else if (this.path) {
        conf = confs[this.path] || {};
      } else {}

      // 引用其他规则
      conf = this.getUseConf(conf, confs);
      return conf;
    },
    label_() {
      const label = this.label || this.conf_.label;
      return this.$demoi18n(label);
    },
    labelTopClsName() {
      return this.labelTop ? 'labelTop' : '';
    },
    hasLabelProp() {
      const label = this.label ?? this.conf_.label ?? null;
      if (label === null && !this.$slots.label) {
        return false;
      }
      return true;
    },
    prop_() {
      if (this.path) {
        return ''; // 交给valueInputer校验
      }
      if (this.prop) {
        return this.prop;
      }
      return '';
    },
    type() {
      return this.conf_.type;
    },
    isFieldShow() {
      if (!this.form) {
        return false;
      }
      if (!this.path) {
        return false;
      }
      if (this.lastObj[this.lastKeySwitch] === false) {
        return false;
      }
      return true;
    },
    valueType() {
      const map = {
        input: 'Input',
        text: 'String',
        url: 'String',
        number: 'Number',
        boolean: 'Boolean',
        date: 'Date',
        enum: 'List',
        color: 'Color',
        angle: 'Number',
        radio: 'Radio',
        radioBtn: 'RadioBtn',
        vector: 'Vector',
        checkboxGroup: 'CheckboxGroup',
      };
      return map[this.type];
    },
    componentStyle() {
      const { componentStyle } = this.form || {};
      return componentStyle;
    },
    stepStrictly() {
      return this.conf_.stepStrictly ?? false;
    },
    contStyle() {
      const style = {};
      if (this.contWidth) {
        style.width = this.contWidth;
      }
      return style;
    },
  },
  watch: {
    componentStyle(componentStyle) {
      let df = this.conf_.default;
      if (df && df[componentStyle]) {
        if (this.path === 'url') {
          df = this.$demoi18n(df[componentStyle]);
        } else {
          df = df[componentStyle];
        }
        this.lastObj[this.lastKey] = df;
      }
    },
    lastObj() {
      this.fixLastObj();
    },
    form() {
      this.init();
    },
  },
  created() {
    this.init();
  },
  methods: {
    init() {
      if (this.path && this.form) {
        this.register();
        this.initLastObj();
        this.initLastKey();
      }
    },

    // 返回倒数第二层对象，用于绑定v-model
    initLastObj() {
      const arr = this.path.split('.');
      const len = arr.length;
      let { form } = this;
      for (let i = 0; i < len; i++) {
        const key = arr[i];
        if (i < len - 1) {
          form = form[key];
        }
      }
      this.lastObj = form;
    },

    // 返回属性路径最后一个key
    initLastKey() {
      const arr = this.path.split('.');
      const lastKey = arr.pop();
      this.lastKey = lastKey;
      if (this.conf_.units) {
        this.lastKeyUnit = `${lastKey}_unit`;
      }
      if (objHas(this.conf_, 'switch')) {
        this.lastKeySwitch = `${lastKey}_switch`;
      }
    },

    // 注册属性
    register() {
      const vm = this;
      const { path } = this;
      const { conf_ } = this;
      const arr = path.split('.');
      const len = arr.length;

      let { form } = this;
      for (let i = 0; i < len; i++) {
        const key = arr[i];
        const nextKey = arr[i + 1];
        if (!objHas(form, key)) {
          if (i === len - 1) {
            let df = conf_.default;
            if (df && df[this.componentStyle]) {
              df = df[this.componentStyle];
            }
            form[key] = df;
          } else {
            if (/^\d+$/.test(nextKey)) {
              // series.0中的0
              form[key] = [];
            } else {
              form[key] = {};
            }
          }
        }

        // 开关，单位注册
        if (i === len - 1) {
          if (objHas(conf_, 'switch')) {
            const switchKey = `${key}_switch`;
            const switchVal = objHas(form, switchKey) ? form[switchKey] : conf_.switch;
            form[switchKey] = switchVal;
          }
          if (conf_.units && conf_.units.length) {
            const unitKey = `${key}_unit`;
            const unit = form[unitKey] || conf_.dfUnit || conf_.units[0];
            form[unitKey] = unit;
          }
        }

        form = form[key];
      }

      return true;
    },

    getRules() {
      if (this.rules) {
        return this.rules;
      }
      let rules = [];
      const { type } = this.conf_;
      let { required, specilChar } = this.conf_;
      const label = this.label_ || this.$demoi18n('placeholder.inputValue');
      required = Boolean(required);
      specilChar = Boolean(specilChar);

      switch (type) {
        case 'url':
          rules = generateUrlRule();
          break;
        case 'text':
        case 'date':
          rules = generateRules({ label, required, specilChar });
          break;
        case 'enum':
          if (this.conf_.options) {
            const isAllStr = this.conf_.options.every(n => typeof n.value === 'string');
            if (isAllStr) {
              rules = generateRules({ label, required });
            }
          }
          break;
        case 'number':
          if (required) {
            rules = genRequireRule({ label });
          }
          break;
        default: break;
      }
      return rules;
    },

    getUseConf(conf, confs) {
      let _conf = { ...conf };
      delete _conf.use;
      if (conf.use) {
        _conf = {
          ...(confs[conf.use] || {}),
          ..._conf,
        };
      }

      if (_conf.use) {
        return this.getUseConf(_conf, confs);
      } else {
        return _conf;
      }
    },

    change(val) {
      this.$emit('change', val);
    },

    // 顶层对象内存地址不一致修正
    fixLastObj() {
      if (this.path && this.path.split('.').length === 1) {
        this.lastObj = this.form;
      }
    },

    objHas,
  },
};
</script>
<style lang="less" scoped>
.vs-form-item {
  margin-bottom: 0;
  :deep(.el-form-item__content) {
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    align-items: flex-start !important;
    min-height: 40px;

    .el-form-item__error {
      white-space: normal;
      word-break: break-word;
      margin-bottom: 10px;
    }
  }
  .cont {
    display: flex;
    align-items: center;
    width: 100%;
    > * {
      margin-left: 10px;
      &:first-child {
        margin-left: 0;
      }
    }
    :deep(.units) {
      flex-basis: 52px;
      flex-shrink: 0;
      flex-grow: 1;
      .el-radio-button__inner {
        padding: 6px;
      }
    }
    :deep(.el-radio-group){
      max-width: 100%;
    }
  }
  :deep(.el-form-item__label) {
    display: flex;
    justify-content: flex-end;
  }
  .label {
    max-width: 100%;
    .label-content {
      display: flex;
      justify-content: flex-end;
      width: max-content;
      width: 100%;
    }
    .label-text {
      flex-grow: 1;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
  }
  &.noLabel{
    :deep(.el-form-item__label) {
      display: none;
    }
  }
  &.is-required{
    .label{
      max-width: calc(100% - 10px);
    }
  }
  &.labelTop{
    :deep(.el-form-item__label){
      align-self: baseline;
    }
  }
}
</style>
